package analyse

import (
	"bufio"
	"log"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

var compile *regexp.Regexp

type AnalyseResult struct {
	Items []StatisticsItem
}

type StatisticsItem struct {
	RequestPath string
	TotalTime   time.Duration
	Count       int
}

func (s StatisticsItem) GetAvgTime() time.Duration {
	return s.TotalTime / time.Duration(s.Count)
}

// 日志单行数据
type logLine struct {
	ip             string
	logDate        time.Time
	httpMethod     string
	requestPath    string
	httpProtocol   string
	responseStatus int
	requestTime    time.Duration
}

func parseLogFormat(logFormat string) {
	strings.ReplaceAll(logFormat, "%t", "\\[(.+)\\]")
	strings.ReplaceAll(logFormat, "%a", "\\d+\\.\\d+\\.\\d+\\.\\d+")
	//strings.ReplaceAll(logFormat, "%r", )
}

// 分析
func Analyse(filePaths []string, logFormat string) AnalyseResult {

	compile = regexp.MustCompile("\\[(.+)\\]\\s(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s\"(.+)\\s(.+)\\s(.+)\"\\s(\\d+)\\s\\((\\d+)\\sms\\)")
	var lines = make([]logLine, 0)
	for _, filePath := range filePaths {
		lines = append(lines, analyseOne(filePath)...)
	}
	itemMap := make(map[string]StatisticsItem, 0)
	for _, line := range lines {
		item, ok := itemMap[line.requestPath]
		if !ok {
			item = StatisticsItem{
				RequestPath: line.requestPath,
				TotalTime:   line.requestTime,
				Count:       1,
			}
			itemMap[line.requestPath] = item
			continue
		}
		totalTime := line.requestTime + item.TotalTime
		count := item.Count + 1
		item.TotalTime = totalTime
		item.Count = count
		itemMap[line.requestPath] = item
	}
	itemList := make([]StatisticsItem, 0)
	for _, v := range itemMap {
		itemList = append(itemList, v)
	}
	result := AnalyseResult{Items: itemList}

	return result
}

// 分析
func analyseOne(filePath string) (lines []logLine) {
	file, err := os.Open(filePath)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lineText := scanner.Text()
		lineStrs := lineMatch(lineText)
		line := resolveLine(lineStrs)
		lines = append(lines, line)

	}
	return
}

func resolveLine(lineStrs []string) logLine {
	dateStr := lineStrs[1]
	ip := lineStrs[2]
	httpMethod := lineStrs[3]
	requestPath := lineStrs[4]
	httpProtocol := lineStrs[5]
	responseStatusStr := lineStrs[6]
	requestTimeStr := lineStrs[7]
	var item = logLine{}
	item.ip = ip
	logDate, err := time.Parse("02/Jan/2006:15:04:05 -0700", dateStr)
	if err != nil {
		log.Fatal(err)
	}
	item.logDate = logDate
	item.httpMethod = httpMethod
	item.requestPath = strings.Split(requestPath, "?")[0]
	item.httpProtocol = httpProtocol
	responseStatusInt, err := strconv.Atoi(responseStatusStr)
	item.responseStatus = responseStatusInt
	if requestTimeStr == "-" {
		item.requestTime = time.Millisecond * 10
	} else {
		requestTime, err := strconv.ParseInt(requestTimeStr, 10, 64)
		if err != nil {
			log.Fatal(err)
		}
		item.requestTime = time.Millisecond * time.Duration(requestTime)
	}
	return item
}

func lineMatch(lineText string) []string {
	return compile.FindStringSubmatch(lineText)

}
